﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<map>
#include<string>
#include<assert.h>
#include<list>
#include<algorithm>
using namespace std;

struct Point
{
	int _x;
	int _y;
};

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year),
		_month(month),
		_day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}

	Date(const Date& d)
		:_year(d._year),
		_month(d._month),
		_day(d._day)
	{
		cout << "Date(const Date& d)" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};


// 一切皆可用列表初始化，且可以不加= 

//int main()
//{
//	//C++ 98支持
//	int a1[] = { 1,1,1,1,1 };
//	int a2[5] = { 0 };
//	Point p = { 1,2 };
//
//	//C++ 11 支持的
//	//内置类型 也支持用  {}   进行初始化
//	int x1 = { 1 };
//
//	 // 自定义类型支持 
//	 // 本质是用 { 2025, 01, 01} 构造一个Date临时对象 
//	 // 临时对象再去拷贝构造d1，编译器优化后合二为一变成 { 2025, 1, 1} 直接构造初始化d1
//	 // 运行一下，可以验证上面的理论，是没调用拷贝构造的
//	Date d1 = { 2025,01,01 };
//
//	//d2引用的是 {2025,07,25}    构造的临时对象（临时对象具有常性   不能修改   必须要加上const才能用）
//	const Date& d2 = { 2025,07,25 };   //这里只是构造了临时对象   引用的就是临时对象
//
//
//	//注：C++ 98支持单参数时类型转换，可以不使用 {}
//	Date d3 = { 2025 };    //C++ 11
//	Date d4 = 2025;        //C++ 98
//	
//
//	//可以省略掉  =
//	Point p1{ 1,1 };
//	int x2{ 2 };
//	Date d6{ 11,11,11 };
//	const Date& d7{ 2025,03,11 };
//
//
//	//只有 {} 初始化，才能省略 =
//	//Date d 2025;          这个就不支持
//
//	vector<Date> v;
//	v.push_back({ 2025,03,11 });
//
//	//map 支持多参数的隐式类型转换    pair
//	map<string, string> dict;
//	dict.insert({ "xxx" ,"yyy"});
//
///*
//	vector  支持任意多个参数
//	可以把花括号传给 initializer_list   C++ 11提供的一个类模板
//	当把花括号给一个对象   就会识别传给initializer_list
//
//	initializer_list   (构造 + 迭代器 + size)   支持范围for 也支持 迭代器的遍历   只读不写
//*/
//	
//	//这两个并不是
//	//这两个是    构造 + 拷贝构造 + 优化   （优化之后  就是直接构造）
//	vector<int> v1 = { 1,2,3,4 };
//	vector<int> v2= { 10,20,30 };
//
//	vector<int> v4{ 1,2,3,4 };
//	vector<int> v5{ 1,1,1,1,1,1,1 };
//	//正常的  vector<int>& v6{1,1,1,1,1}    这种是不行的
//
//	//需要加上 const修饰才能进行引用
//	const vector<int>& v6{ 1,1,1,1,1 };
//
//	//这个是构造
//	vector<int> v3({ 10,20,30,1,1,1,1,1 });
//
//	//这两个原理类似
//	initializer_list<int> il1 = { 10,20,30,1,1,1,1,1,1 };    
//	//把数组拷贝过来  然后在栈上开辟一段空间   有两个指针指向这段数组的开始和结束
//	
//	int a1[]  = { 10,20,30,1,1,1,1,1,1 };   //a1是数组  会在栈上开一段空间
//
//
//	//map 支持这种初始化
//	// initializer_list + {}pair初始化隐式类型转换
//	map<string, string> dict = { {"xxxx","yyyy"},{"sort","zzzz"} };
//
//	return 0;
//}



//int main()
//{
//	//左值：可以取地址
//	//以下 p、b、c、*p、s、s[0]  就是常见的左值
//	int* p = new int(0);
//	int b = 1;
//	const int c = b;
//	*p = 10;
//	string s("1111111");
//	s[0] = 'x';
//
//	//c会输出地址    但是s[0]  不进行强转成指针类型是不会进行输出地址的
//	cout << &c << endl;
//	cout << (void*)&s[0] << endl;
//	//但是他们都可以取地址    所以他们都是左值     cout无法打印char*  的地址
//
//	//右值：不能取地址
//	double x = 1.1, y = 2.2;
//	//下面的 10，x+y, fmin(x,y),string("1111")  都是常见右值
//	//常量
//	10;
//	x + y;
//	fmin(x, y);
//	string("11111");
//
////均会报错    说明需要左值  
//	//cout << &10 << endl;
//	//cout << &(x+y) << endl;
//	//cout << &(fmin(x, y)) << endl;
//	//cout << &string("11111") << endl;
//
//
//
////左值引用就是给左值取别名     右值引用就是给右值取别名
//	int& r1 = b;
//	int*& r2 = p;
//	int& r3 = *p;
//	string& r4 = s;
//	char& r5 = s[0];
//
//	int&& rr1 = 10;
//	double&& rr2 = x + y;
//	double&& rr3 = fmin(x, y);
//	string&& rr4 = string("1111");
//
////左值引用不能直接引用右值     但是const 左值引用可以引用右值
//	const int& rx1 = 10;
//	const double& rx2 = x + y;
//	const double& rx3 = fmin(x, y);
//	const string& rx4 = string("2222");
//
//// 右值引用不能直接引用左值   但是右值引用可以引用move(左值)
//	//int&& rrx = b;     这个就是不对的
//	int&& rrx1 = move(b);
//	int*&& rrx2 = move(p);
//	int&& rrx2 = move(*p);
//	string&& rrx4 = move(s);
//
//	string&& rrx5 = (string&&)s;     //强制类型转换
////move  是一个函数模板     可以接收右值
//
//	//b   r1    rr1 都是变量表达式   都是左值
//	cout << &b << endl;
//	cout << &r1 << endl;
//	cout << &rr1 << endl;
//	
//	int i = 1;
//	int* ptr = (int*)i;
///* 注意：强制类型转换是不会改变一个对象本身的属性 */
//
//	
////rr1是右值引用  属性是左值   右值引用本身的属性又会被变成左值  所以右值引用只能被左值引用引用 不能被右值引用引用  除非move一下
//	//int&& rr1 =10;
//// 这里注意：rr1的属性是左值，所以不能再被右值引用绑定，除非move
//	int& r6 = rr1;
//
//	int&& rrx6 = move(rr1);
//	return 0;
//}



//void f(int& x)
//{
//	std::cout << "左值引用重载 f（" << x << "）\n";
//}
//
//void f(const int& x)
//{
//	std::cout << "到const 的左值引用重载 f(" << x << ")\n";
//}
//
//void f(int&& x)
//{
//	std::cout << "右值引用重载f(" << x << ")\n";
//}
//
//int main()
//{
//	//std::string s1 = "Test";
//	////错误示范：std::string&& r1 = s1;     不能绑定左值
//
//	//const std::string& r2 = s1 + s1;    //搭配 const 的左值引用延长生存期
//	//// r2 += "Test";       错误示范：不能通过到const 的引用修改
//
//	//std::string&& r3 = s1 + s1;    //正确   右值引用延长生存期
//	//r3 += "Test";     
//
//	
//
//	//编译器会调用最匹配的
//	int i = 1;
//	const int ci = 2;
//
//	f(i);       //调用  f(int&)
//	f(ci);		//调用  f(const int&)
//	f(3);		//调用  f(int&&)   如果没有f(int&&)重载   则会调用f(const int&)
//	f(std::move(i));     //调用f(int&&)
//
//
//	//右值引用变量在用于表达式时是左值
//	//右值引用本身的属性是左值     x是可以修改的
//	int&& x = 1;
//	f(x);    //调用f(int& x)    右值本身的属性是左值   也就是会匹配f(int& x)
//	f(std::move(x));     //这个就会调用f(int&& x)
//
//	return 0;
//}



//不能用左值引用返回
//class Solution {
//public:
//	// 传值返回需要拷⻉    不能用左值和右值引用返回
//	string addStrings(string num1, string num2) {
//		string str;
//		int end1 = num1.size() - 1, end2 = num2.size() - 1;
//		// 进位 
//		int next = 0;
//		while (end1 >= 0 || end2 >= 0)
//		{
//			int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
//			int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
//			int ret = val1 + val2 + next;
//			next = ret / 10;
//			ret = ret % 10;
//			str += ('0' + ret);
//		}
//		if (next == 1)
//			str += '1';
//		reverse(str.begin(), str.end());
//		return str;    //返回对象的别名   但是局部对象出来就会销毁   所以返回引用和野指针类似
//	}
//};
//因为上面的str属于对应的一块栈帧   即使延长生命周期还是会被销毁   没有地方存储
//当返回是一个局部对象的时候   只能运用传值返回


//class Solution {
//public:
//	// 这里的传值返回拷贝代价就太大了 
//	vector<vector<int>> generate(int numRows) {
//		vector<vector<int>> vv(numRows);
//		for (int i = 0; i < numRows; ++i)
//		{
//			vv[i].resize(i + 1, 1);
//		}
//		for (int i = 2; i < numRows; ++i)
//		{
//			for (int j = 1; j < i; ++j)
//			{
//				vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
//			}
//		}
//		return vv;
//	}
//};



namespace lcx
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

	//构造
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			cout << "string(char* str) -- 构造" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}
	
	//交换函数
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

	
	//拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s)---- 拷贝构造" << endl;
			//扩容  拷贝
			reserve(s._capacity);
			for (auto ch : s)
			{
				push_back(ch);
			}
		}

	//移动构造
		string(string&& s)
		{
			cout << "string(string&& s) --- 移动构造" << endl;
			swap(s);
		}

	//拷贝赋值
		string& operator=(const string& s)
		{
			cout << "string& operator=(const string& s) -- 拷贝赋值" << endl;

			if (this != &s)
			{
				_str[0] = '\0';
				_size = 0;

				reserve(s._capacity);
				for (auto ch : s)
				{
					push_back(ch);
				}
			}
			return *this;
		}

	//移动赋值
		string& operator=(string&& s)   //这里的移动赋值也要传右值
		{
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);
			return *this;
		}

	//析构
		~string()
		{
			//cout << "~string() -- 析构" << endl;
			delete[] _str;
			_str = nullptr;
		}

	//赋值重载
		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		//扩容函数
		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				if (_str)
				{
					strcpy(tmp, _str);
					delete[] _str;
				}
				_str = tmp;
				_capacity = n;
			}
		}

		//压栈尾插函数
		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : 2 * _capacity;
				reserve(newcapacity);
			}
			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}


	// += 操作
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

	//对应 字符串
		const char* c_str() const
		{
			return _str;
		}
	
	//返回大小
		size_t size() const
		{
			return _size;
		}

private:
	char* _str = nullptr;
	int _size = 0;
	int _capacity = 0;
	};
}

/*
	直接构造一个对象，如果不优化对应：构造，拷贝构造  构造，拷贝构造   构造，拷贝构造，拷贝构造
	一代优化对应： 构造   构造   构造   拷贝构造
	二代优化对应： 构造   构造   构造

	先定义一个对象，再进行接收赋值：
		不优化：构造，构造，拷贝构造   构造，拷贝构造   构造，拷贝构造，拷贝赋值
		一代优化：构造，构造，构造，构造，拷贝构造，拷贝赋值
		二代优化；构造，构造，构造，构造，拷贝赋值

C++ 11(有了 移动构造 和 移动赋值       之前的优化都变成了锦上添花 而非雪中送炭)
	右值不能修改，右值引用引用右值之后    属性变成左值 
	C++ 11 出现之后不优化：  构造，移动构造，构造，移动构造，构造，(移动构造，移动构造)
	优化：构造，构造，构造，移动构造
	最终优化：构造，构造，构造

	先定义一个对象，再进行赋值
	不优化：构造，构造，移动构造，构造，移动构造，构造，移动构造，移动赋值
	优化：构造，构造，构造，(构造，移动构造)，移动赋值
	终极优化：构造，构造，构造，构造，移动赋值

*/


class Solution {
public:
	// 传值返回需要拷贝    不能用左值和右值引用返回
	lcx::string addStrings(lcx::string num1,lcx::string num2) {
		lcx::string str;
		int end1 = num1.size() - 1, end2 = num2.size() - 1;
		// 进位 
		int next = 0;
		while (end1 >= 0 || end2 >= 0)
		{
			int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
			int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
			int ret = val1 + val2 + next;
			next = ret / 10;
			ret = ret % 10;
			str += ('0' + ret);
		}
		if (next == 1)
			str += '1';
		reverse(str.begin(), str.end());
		cout << "***********" << endl;
		return str;    //返回对象的别名   但是局部对象出来就会销毁   所以返回引用和野指针类似
	}
};


//int main()
//{
//	////构造
//	//lcx::string s1("lcx");
//	//
//	////拷贝构造
//	//lcx::string s2 = s1;
//
//	////构造 + 移动构造   优化后直接构造
//	//lcx::string s3 = lcx::string("lcx");
//
//	////移动构造
//	//lcx::string s4 = move(s1);
//	//cout << "xxxxxxxxxxxxxxxxxxx" << endl;
//
////在19中可以见得  移动构造   但是22就只有构造直接三个对象合三为一(不产生临时对象  也没产生str对象  只产生了str的引用  只是ret的引用  不会产生拷贝构造)
//
////这个就只有构造
//	lcx::string ret =Solution().addStrings("11111", "222222");
//	cout << ret.c_str() << endl;
//
////这个只会显示  移动赋值   会进行优化   没有移动赋值就会拷贝赋值
//	//lcx::string ret;
//	//ret = Solution().addStrings("11111", "2222");
//	//cout << ret.c_str() << endl;
//
//	return 0;
//}


//左值引用的版本的模板
//template<class T>
//void f1(T& x)
//{}
//
// 
////由于引用折叠限制   f2实例化后可以是左值引用，也可以是右值引用
//template<class T>
//void f2(T&& x)
//{}
//
// 
////这是万能引用模版(传左值就是左值引用   传右值就是右值引用)
//template<class T>
//void Function(T&& t)
//{
//	int a = 0;
//	T x = a;
//	//x++;
//	cout << &a << endl;
//	cout << &x << endl << endl;
//}



//引用的引用(会导致一个引用折叠)
//int main()
//{
//	typedef int& lref;
//	typedef int&& rref;
//	int n = 0;
//
//	//引用折叠（一左则左   全右才是右）
//	lref& r1 = n;       //r1 的类型是 int&
//	lref&& r2 = n;      //r2 的类型是 int& 
//	rref& r3 = n;       //r3 的类型是 int&
//	rref&& r4 = 1;      //r4 的类型是 int&&    这个无法引用n  右值引用无法直接引用左值   只能move之后
//
//  这里面的都是显示实例化   但是一般情况下不会显示实例化   都是自动推
// 
//	//没有折叠 --> 实例化为 void f1(int& x)
//	f1<int>(n);
//	//f1<int>(0);   //报错   这是右值
//
//	//折叠 --> 实例化为void f1(int& x)
//	f1<int&>(n);    //左值引用
//	//f1<int&>(0);    //报错   这里折叠之后仍是左值引用
//
//	//折叠 --> 实例化为 void f1(int& x)
//	f1<int&&>(n);
//	//f1<int&&>(0);   //报错
//
//	//折叠 --> 实例化为void f1(const int& x)
//	f1<const int&&>(n);
//	f1<const int&&>(0);     //因为引用折叠限定  这里对f1无论怎么进行实例化   总会是一个左值引用   最多加const  变成const左值引用
//
//
//	//没有折叠  --> 实例化为void f2(int&& x)
//	//f2<int>(n);     //报错
//	f2<int>(0);
//
//	//折叠  实例化为void f2(int& x)
//	f2<int&>(n);
//	//f2<int&>(0);     //报错
//
//	//折叠 -->实例化为void f2(int&& x)
//	//f2<int&&>(n);    //报错
//	f2<int&&>(0); 
//
//	return 0;
//}



//这是自动推理    传右值就是右值引用   传左值会导致引用折叠，就会是左值引用
//int main()
//{
//	//10 是右值  推导出T为int   模版实例化为void Function(int&& t)
//	//Function(10);    //右值
//
//	int a;
//	//a 是左值，推导出T为int& ，引用折叠，模版会实例化  推成void Function(int& t)
//	//Function(a);     //左值   地址和x一样   所以是左值
//
//	//std::move(a)是右值，推导出T为int，模版实例化为void Function(int&& t)
//	//Function(std::move(a));    //左值
//
//	const int b = 8;
//	//b是左值，推导出T为const int&,引用折叠，模版实例化为void Function(const int& t)
//	//所以Function内部会编译报错  x不能++
//	//Function(b);    //const 左值    不能给常量赋值
//
//	
//	//std::move(b) 右值，推出T为const int，模板实例化为void Function(const int&& t)    
//	//t是右值不能修改  但是加了引用就可以修改  但是又被const修改 
//	//所以Function内部会编译报错   x不能++
//	Function(std::move(b));      //const 右值   不能给常量赋值     输出地址不同  因为这里不是引用
//	
//
//	return 0;
//}


//void Fun(int& x) { cout << "左值引用" << endl; }
//void Fun(const int& x) { cout << "const 左值引用" << endl; }
//void Fun(int&& x) { cout << "右值引用" << endl; }
//void Fun(const int&& x) { cout << "const 右值引用" << endl; }
//
//template<class T>
//void Function(T && t)    //这里有可能是左值也可能是右值   但是一旦再向下传一层参数   就会导致全部都变成了左值引用
//{
//	//完美转发的模板   forward   是左值就保持左值   是右值就强转
//	Fun(forward<T> (t));   //完美转发的意思就是保持它的属性往下一层传递    传一个T就可以（这样才是原来的类型）
//}
//
//int main()
//{
//	//10是右值  推导出T为int  模板实例化为 void Function(int&& t)
//	Function(10);   //右值
//
//	//a是左值  推导出T是int&  引用折叠  模板实例化为void Function(int& t)
//	int a;
//	Function(a);  //左值   左值引用
//
//	//std::move(a)是右值  推导出T为int  模板实例化为void Function(int& t)
//	Function(std::move(a));     //右值
//	const int b = 8;
//
//	//a是左值   推导出T为const int&   引用折叠   模版实例化为 void Function(const int& t)
//	Function(b);
//
//	//std::move(b)  是右值   推导出T为const int     模版实例化为void Function(const int&& t)
//	Function(std::move(b));    //const 是右值
//
//
//	return 0;
//}


//C++ 11 之前无论是否传右值  都是 构造 + 拷贝构造


// 注意：下面这串代码，如果是一个左值   那么就是 构造 + 拷贝构造
// 如果是一个move以后的左值（将亡值   构造+移动构造）
// 纯右值 构造 + 移动构造
//int main()
//{
//	//构造
//	lcx::string s1("1111111");
//
//
//	//拷贝构造
//	list<lcx::string> lt;
//	lt.push_back(s1);    
//
//	//移动构造（效率高）
//	lcx::string s2("3333333");
//	lt.push_back(move(s2));    
//
//	//构造 + 移动构造
//	lt.push_back("22222222222");
//
//	return 0;
//}




// emplace_back总体而言是更高效，推荐以后使用emplace系列替代insert和push系列 
int main()
{
	list<lcx::string> lt;
	// 传左值，跟push_back一样，走拷贝构造 
	lcx::string s1("111111111111");
	lt.emplace_back(s1);
	cout << "*********************************" << endl;

	// 右值，跟push_back一样，走移动构造 
	lt.emplace_back(move(s1));
	cout << "*********************************" << endl;

	// 直接把构造string参数包往下传，直接用string参数包构造string 
	// 这里达到的效果是push_back做不到的 
	lt.emplace_back("111111111111");
	cout << "*********************************" << endl;
	list<pair<lcx::string, int>> lt1;

	// 跟push_back一样 
	// 构造pair + 拷贝/移动构造pair到list的节点中data上 
	pair<lcx::string, int> kv("苹果", 1);
	lt1.emplace_back(kv);
	cout << "*********************************" << endl;

	// 跟push_back一样 
	lt1.emplace_back(move(kv));
	cout << "*********************************" << endl;

	// 直接把构造pair参数包往下传，直接⽤pair参数包构造pair 
	// 这⾥达到的效果是push_back做不到的 
	lt1.emplace_back("苹果", 1);
	cout << "*********************************" << endl;
	return 0;
}
